Repository navigation
Public RenderOptions, FindReferencedTemplates and sandbox policy (0357 S2b, S2c) - #811
Conversation
…lates (0357 S2b) RenderTo(out|sink, params, RenderOptions) renders with the caller's own globals, shared so that a value a callable keeps outlives the render, and a poll that may throw to stop it. A poll alone makes the render count its steps; a render a polled one starts is polled too. FindReferencedTemplates is public; in a wide template it gave nullopt for every name and now converts them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
…; test includes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
…:SecurityError (0357 S2c) Settings::sandboxPolicy holds a public ISandboxPolicy, which one bridge turns into the engine's policy (renamed IEngineSandboxPolicy). Its Format may decline: the engine's own str.format then reads each field's attribute through the policy, as Jinja2's SandboxedFormatter does. Settings::immutableContainers is the public switch for the immutable sandbox. A refused attribute fails with the new ErrorCode::SecurityError instead of an UndefinedError with a marker, and UndefinedDescription::security makes and reads one. A template keeps the policy it was loaded with (0427, done). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
…tidy fixes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
|
@codex review Generated by Claude Code |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: af5416c0fc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex on #811: a template loaded without limits had no step counting on the items a for-loop's if-filter drops, and a big-integer backend alone installed inactive limits, so RenderOptions::poll never ran. The filter loop now counts a step per item, and a poll with no step limit set gets the poll-only limits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
|
@codex review Both P2 findings are fixed in e740760, with regression tests. Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e740760da5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex on #811: RenderOptions::globals were converted before RenderCore, so a host BigInt past the 2^20-bit cap threw out of RenderTo instead of returning ResourceLimitExceeded, and the conversion ran outside the template's limits scope. RenderCore now converts them after installing the limits, inside its boundary, as it does the params. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
|
@codex review The round-2 P2 (the conversion of per-render globals was outside the error boundary) is fixed in da85d26, with a regression test. This is the last re-request for this PR. Generated by Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: da85d26371
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex on #811: a render a polled one starts, on an environment with a custom big-integer backend and no limits (non-Boost build), installed a scope with inactive limits and was never polled. RenderLimitsScope now counts steps for an inherited poll whenever its limits set none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
The perf track held #811 on a +14 instruction cost on every render. Callgrind put it all in template.cpp's copy of ~RenderContext, the one the linker keeps: with RenderCore<true> compiled in the same file, GCC called a robin_hood table destructor out of line there. The RenderOptions entry point (TemplateImpl::RenderWithOptions) now lives in src/template_render_options.cpp, and plain_text and substitute renders count the same as master. The TemplateParser constructor is forced inline, since the move left Load/plain_text +0.51%; it is now +0.24%, 6 of the 9 instructions being the Settings comparison of the two new fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AWNL7n7c5XUg2Xoo4ZRjLn
Marks 0427 done in the index. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DTQTriEsFrrBgcYNKDUUF4
Sync the task index after #811
Requested by Ruslan · project thread
Problem
Task 0357 moves the Python module from private engine seams to the public API before the G1 freeze (plan docs/design/0357-python-module-public-api.md, approved 2026-11-06). #800 landed the public host object (S1a, S2a). Three seams were still private:
RenderInternal,t_hostPoll);ReferencedTemplatesOf;This PR makes all three public: B3, B6 and B7/D6b. The module itself switches in S3.
Resulting behaviour
S2b (B3, B6)
jinja2::RenderOptions{ shared_ptr<const ValuesMap> globals; std::function<void()> poll; }andTemplate::RenderTo(out | sink, params, options).LendGlobal).GetException().Template::FindReferencedTemplates()is now public.test/referenced_templates_test.cppnow builds in shared mode.nullopt. Fixed, with a test row.S2c (B7, D6b)
jinja2::ISandboxPolicyinjinja2cpp/sandbox_policy.h, held bySettings::sandboxPolicy(compared by identity).NativeAttribute(const Value&, string_view) -> optional<Value>is asked wherever the engine's policy was asked before.Format(...) -> optional<Value>returns nullopt by default. The engine's ownstr.formatthen reads each field's attribute throughNativeAttribute, as Jinja2'sSandboxedFormatterdoes:'{0.__class__}|'.format(s)gives|.IEngineSandboxPolicy, with one bridge (src/public_sandbox_policy.cpp), as for host objects.Settings::immutableContainersis the public switch for the immutable sandbox.ErrorCode::SecurityError(21) replaces theextraParams[1]marker on anUndefinedError.UndefinedDescription::securitymakes and reads a refused attribute's undefined value.HostPollScope, the SecurityError code mapping, the rename. Its render entry is unchanged until S3.Validation
scripts/preflight.sh --perf: all checks pass.Settings ==comparison of the two new fields; Render/for_filter_if +0.30% (a step per item the filter skips).~RenderContext, which called a robin_hood table destructor out of line onceRenderCore<true>was compiled in the same file.TemplateImpl::RenderWithOptionsnow lives insrc/template_render_options.cpp, and theTemplateParserconstructor is forced inline.SandboxedEnvironment,ImmutableSandboxedEnvironment,meta.find_referenced_templates).formatMapwas never set for a public policy. The header now saysformat_mapcomes fromNativeAttribute, as the Python module does it.Limits
callerreachesNativeAttributeas an empty value. S3 must keep the module's stand-in object for them.TemplateEnvImpl::SetSandboxPolicyandSetDialectstay internal until the module switches (S3) and are deleted in S4.Roles: verifier ×1 (1 round, ready). Red CI pushes: 1 (dec3a05: clang-tidy misc-include-cleaner in the new src/template_render_options.cpp; local preflight skipped the file because build/ had not been reconfigured).
Codex: 4 findings in 3 rounds, 4 fixed, 0 declined (e740760: a loop filter's skipped items and a backend-only limits scope now reach
RenderOptions::poll, Render/for_filter_if +0.30%; da85d26: per-render globals are converted inside the render's limits scope and error boundary; 859ce81: a nested render under a backend-only scope is polled too). Both re-requests are used, so the last fix has no Codex re-review.Generated by Claude Code